package com.wish.nio;

import com.wish.common.MyUtils;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;


/**
 * @author tantexian
 * @since 2016/6/24
 */
public class NIOClient {

    private static Selector selector;
    private static SocketChannel socketChannel;


    public static void main(String[] args) {
        final int port = args.length >= 1 ? Integer.parseInt(args[0]) : MyUtils.getDefaultPort();
        final String serverAddr = args.length >= 2 ? args[1] : MyUtils.getDefaultServerAddr();

        try {
            selector = Selector.open();
            socketChannel = SocketChannel.open();
            socketChannel.configureBlocking(false);
        }
        catch (IOException e) {
            e.printStackTrace();
            System.exit(1);
        }

        new Thread(new Runnable() {
            public void run() {
                try {
                    tryToConnectServer();
                }
                catch (Exception e) {
                    e.printStackTrace();
                    //System.exit(1);
                }

                while (true) {
                    try {
                        // 阻塞到至少有一个通道在你注册的事件上就绪了(超时时间为1000ms，每隔1超时唤醒执行一次)
                        // 返回的int值表示有多少通道已经就绪
                        selector.select(1000);
                        Set<SelectionKey> selectionKeys = selector.selectedKeys();
                        Iterator<SelectionKey> iterator = selectionKeys.iterator();
                        while (iterator.hasNext()) {
                            SelectionKey selectionKey = iterator.next();
                            iterator.remove();
                            HandlerSelectionKey(selectionKey);
                        }
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                    }
                }

            }

            private void tryToConnectServer(){
                try {
                    if (socketChannel.connect(new InetSocketAddress(serverAddr, port))) {
                        // 如果直接连接成功，则直接注册为读数据即可
                        socketChannel.register(selector, SelectionKey.OP_READ);
                    }
                    else {
                        socketChannel.register(selector, SelectionKey.OP_CONNECT);
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }).start();

    }


    private static void sendMsg2Server(String msg) throws IOException {
        byte[] bytes = msg.getBytes();
        ByteBuffer byteBuffer = ByteBuffer.allocate(bytes.length);
        byteBuffer.put(bytes);
        byteBuffer.flip();
        socketChannel.write(byteBuffer);
        if(!byteBuffer.hasRemaining()){
           // System.out.println("[send \"" + msg + "\" to server succsessed!]");
        }
    }


    private static void HandlerSelectionKey(SelectionKey selectionKey) {
        try {
            if (selectionKey.isValid()) {
                SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                if (selectionKey.isConnectable()) {// 如果是处于连接状态，说明服务端已经返回ACK应答消息
                    // finishConnect()方法，如果返回值为true，说明客户端连接成功
                    if (socketChannel.finishConnect()) {
                        // 将SocketChannel注册到多路复用器上，注册SelectionKey.OP_READ操作位，监听网络读操作
                        socketChannel.register(selector, SelectionKey.OP_READ);
                        System.out.println("\nPlease input you question (example：time or name)...");
                        new Thread(new Runnable() {
                            public void run() {
                                try {
                                    while (true) {
                                        boolean isSend = false;
                                        while (!isSend){
                                            BufferedReader bufferedReaderSystemIn = new BufferedReader(new InputStreamReader(System.in));
                                            String input = bufferedReaderSystemIn.readLine();
                                            if (input==null || input.length() == 0) {
                                                continue;
                                            }
                                            if(input.contains("exit") || input.contains("bye")){
                                                System.exit(1);
                                                break;
                                            }
                                            sendMsg2Server(input);
                                            isSend = true;
                                        }
                                    }

                                } catch (IOException e) {
                                    e.printStackTrace();
                                }
                            }
                        }).start();
                    }
                    else {
                        // 连接失败，进程退出
                        System.exit(1);
                    }
                }
            }
            if (selectionKey.isReadable()) {
                ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
                int read = socketChannel.read(byteBuffer);
                if (read > 0) {
                    // 将缓冲区limit设置为position，将position设置为0，用于后续对缓冲区读取操作
                    byteBuffer.flip();
                    byte[] bytes = new byte[byteBuffer.remaining()];
                    byteBuffer.get(bytes);
                    String msg = new String(bytes);
                    if(msg.length() > 0){
                        System.out.println("The answer from robot is: " + msg);
                    }
                }
                else if (read < 0) {
                    // 关闭链路
                    selectionKey.cancel();
                    socketChannel.close();
                }
                else {
                    // 当前没有读取到字节
                }
            }
        }
        catch (IOException e) {
            selectionKey.cancel();
            e.printStackTrace();
        }
    }
}
